package genetics;

import java.util.BitSet;

/**
 * GeneString class.
 * @author pcdejager
 *
 */
public class GeneString {
    /**
     * Constructor.
     * @param totalBits The number of bits in the gene string
     */
    public GeneString(final int totalBits) {
        if (totalBits > 0) {
            bits = totalBits;
            genes = new BitSet(totalBits);
        }
    }

    /**
     * Read the gene value.
     * @param start The start position
     * @param end The end position
     * @return The gene value
     */
    public final int readGene(final int start, final int end) {
        if (start > end) {
            return -1;
        }
        if ((start < 0) || (end < 0) || (start >= bits) || (end >= bits)) {
            return -1;
        }
        int result = 0;
        for (int count = end; count >= start; --count) {
            result <<= 1;
            if (genes.get(count)) {
                result |= 1;
            }
        }
        return grayToBinary(result);
    }

    /**
     * Write a gene value to the string.
     * @param start The start position
     * @param end The end position
     * @param value The gene value to write
     * @return True if successful else false
     */
    public final boolean writeGene(final int start, final int end,
            final int value) {
        if (start > end) {
            return false;
        }
        if ((start < 0) || (end < 0) || (start >= bits) || (end >= bits)) {
            return false;
        }
        int result = binaryToGray(value);
        for (int count = start; count <= end; ++count) {
            genes.set(count, ((result & 1) == 1));
            result >>= 1;
        }
        return true;
    }

    /**
     * Convert binary value to gray code.
     * @param num The value to conver
     * @return The resulting gray code
     */
    private int binaryToGray(final int num) {
        return (num >> 1) ^ num;
    }

    /**
     * Convert a gray code to binary.
     * @param num The gray code to convert
     * @return The resulting binary
     */
    private int grayToBinary(final int num) {
        int result = num;
        int mask = 0;
        for (mask = result >> 1; mask != 0; mask = mask >> 1) {
            result = result ^ mask;
        }
        return result;
    }

    /**
     * The number of bits in the gene string.
     */
    private int bits = 0;

    /**
     * The bits in the gene string.
     */
    private BitSet genes = null;
}
